/**
 * $Revision$
 * $Date$
 *
 * Copyright (C) https://gitee.com/baibaiclouds/platform loon. All rights reserved.
 * <p>
 * This software is the confidential and proprietary information of loon.
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the agreements you entered into with loon.
 * 
 * Modified history:
 *   Loon  2019年11月14日 下午9:46:54  created
 */
package com.desktop.web.service.device;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.desktop.web.core.comenum.RemoteProtocolType;
import com.desktop.web.core.comenum.Status;
import com.desktop.web.core.exception.BusinessException;
import com.desktop.web.core.utils.RequestUtil;
import com.desktop.web.core.utils.Util;
import com.desktop.web.service.config.ConfigService;
import com.desktop.web.service.log.LogService;
import com.desktop.web.service.node.NodeService;
import com.desktop.web.service.remotecpe.NatService;
import com.desktop.web.service.remotecpe.VirtulNatService;
import com.desktop.web.service.session.DeviceSessionService;
import com.desktop.web.service.tunnel.TunnelService;
import com.desktop.web.uda.entity.Device;
import com.desktop.web.uda.entity.DeviceSettings;
import com.desktop.web.uda.entity.Node;
import com.desktop.web.uda.entity.NodeDevice;
import com.desktop.web.uda.entity.User;
import com.desktop.web.uda.mapper.DeviceMapper;
import com.desktop.web.uda.mapper.DeviceSettingsMapper;
import com.desktop.web.uda.mapper.NodeDeviceMapper;

/**
 * 
 *
 * @author baibai
 */
@Service
public class DeviceService implements InitializingBean {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Value("${device.timeout.bingkey.max.sec}")
    private Integer DEVICE_TIMEOUT_BINGKEY_SEC;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private NodeDeviceMapper nodeDeviceMapper;

    @Autowired
    private DeviceSettingsMapper deviceSettingsMapper;

    @Autowired
    private DeviceSessionService deviceSessionService;

    @Autowired
    private NatService natService;

    @Autowired
    private VirtulNatService virtulNatService;

    @Autowired
    private TunnelService tunnelService;

    @Autowired
    private ConfigService configService;

    @Autowired
    private NodeService nodeService;

    @Autowired
    private LogService logService;

    @Override
    public void afterPropertiesSet() throws Exception {

    }

    /**
     * 添加设备
     * 
     * @param params
     * @return
     */
    public Device addDevice(Map<String, Object> params) {

        Long nodeId = Long.valueOf(params.get("nodeId").toString());
        nodeService.checkNodeByCuruser(nodeId);

        Device device = new Device();
        device.setSn(Util.UUID());
        device.setIsprober(Status.NO);
        device.setName(params.get("name").toString());
        device.setIp(params.get("ip").toString());
        device.setPort(Integer.valueOf(params.get("port").toString()));
        device.setDevdesc(params.get("devdesc").toString());
        device.setProtocol(RemoteProtocolType.valueOf(params.get("protocol").toString()));

        if (device.getProtocol() == RemoteProtocolType.RDP || device.getProtocol() == RemoteProtocolType.SSH) {
            device.setUsername(params.get("username").toString());
            device.setPassword(params.get("password").toString());
        }

        device.setCtime(new Date());
        device.setSort(device.getCtime().getTime());
        deviceMapper.insert(device);

        NodeDevice nodeDevice = new NodeDevice();
        nodeDevice.setDeviceId(device.getId());
        nodeDevice.setNodeId(nodeId);
        nodeDeviceMapper.insert(nodeDevice);

        logService.addLogCuruser("设备管理", "添加设备信息成功，设备名称：{}，协议类型:{}", device.getName(), device.getProtocol().toString());
        return device;
    }

    /**
     * 添加设备
     * 
     * @param device
     */
    public Device addDevice(Device device) {
        device.setCtime(new Date());
        deviceMapper.insert(device);
        logger.info("add device success,name:{},id:{}", device.getName(), device.getId());
        return device;
    }

    /**
     * 根据设备sn进行查询
     * 
     * @param sn
     * @return
     */
    public Device getDeviceBySN(String sn) {

        if (StringUtils.isEmpty(sn)) {
            return null;
        }

        Device device = new Device();
        device.setSn(sn);
        QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(device);

        device = deviceMapper.selectOne(queryWrapper);
        if (device != null) {
            device.setPassword(null);
        }
        return device;
    }

    /**
     * 更新设备信息
     * 
     * @param oper
     * @param update
     */
    public void updateBySN(Device update) {

        Device tempDevice = this.getDeviceById(update.getId());
        if (tempDevice == null) {
            throw new BusinessException("参数错误");
        }

        deviceMapper.updateById(update);
        logger.info("update device info success,did:{}", tempDevice.getId());
    }

    /**
     * 根据用户获取设备列表
     * 
     * @param nodeId
     * @return
     */
    public List<Device> getDeviceByCurUser(Long nodeId) {
        return null;
    }

    /**
     * 根据id获取设备信息
     * 
     * @param deviceId
     * @return
     */
    public Device getDeviceById(Long deviceId) {
        Device device = deviceMapper.selectById(deviceId);
        if (device == null) {
            return null;
        }

        device.setPassword(null);
        return device;
    }

    /**
     * 获取设备密码
     * 
     * @param deviceId
     * @return
     */
    public String getPasswordById(Long deviceId) {
        Device device = deviceMapper.selectById(deviceId);
        if (device == null) {
            return null;
        }

        return device.getPassword();
    }

    /**
     * 更新设备信息
     * 
     * @param user
     * @param update
     */
    public void updateDevice(User user, Device update) {
        if (update == null || update.getId() == null) {
            throw new BusinessException("错误错误");
        }

        Device tempDevice = getDeviceById(update.getId());
        if (tempDevice == null) {
            throw new BusinessException("错误错误");
        }

        if (StringUtils.isEmpty(update.getPassword())) {
            update.setPassword(null);
        }

        deviceMapper.updateById(update);

        logger.info("user update device success,uid:{},did:{}", user.getId(), update.getId());
    }

    /**
     * 移动设备到指定节点
     * 
     * @param deviceId
     * @param nodeId
     */
    public void moveDevice(Long deviceId, Long nodeId) {

        NodeDevice nodeDevice = new NodeDevice();
        nodeDevice.setDeviceId(deviceId);
        QueryWrapper<NodeDevice> queryWrapper = new QueryWrapper<NodeDevice>();
        queryWrapper.setEntity(nodeDevice);
        NodeDevice tempNodeDevice = nodeDeviceMapper.selectOne(queryWrapper);
        if (tempNodeDevice.getNodeId().equals(nodeId)) {
            return;
        }

        NodeDevice update = new NodeDevice();
        update.setId(tempNodeDevice.getId());
        update.setNodeId(nodeId);
        nodeDeviceMapper.updateById(update);

        logService.addLogCuruser("设备管理", "移动设备节点成功，newnodeid：{}", nodeId);
    }

    /**
     * 获取设备配置信息
     * 
     * @param user
     * @param sn
     * @return
     */
    public DeviceSettings getDeviceSettings(String sn) {
        Device device = this.getDeviceBySN(sn);
        if (!device.getSn().equals(sn)) {
            return null;
        }

        DeviceSettings deviceSettings = new DeviceSettings();
        deviceSettings.setDeviceId(device.getId());
        QueryWrapper<DeviceSettings> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(deviceSettings);

        deviceSettings = deviceSettingsMapper.selectOne(queryWrapper);
        if (deviceSettings == null) {
            deviceSettings = new DeviceSettings();
            deviceSettings.setDeviceId(device.getId());
            deviceSettings.setAutoRemote(Status.YES);
            deviceSettings.setAutoRun(Status.YES);
            deviceSettingsMapper.insert(deviceSettings);
        }

        return deviceSettings;
    }

    /**
     * 更新设备信息
     * 
     * @param user
     * @param sn
     * @param deviceSettings
     */
    public void updateDeviceSettings(String sn, DeviceSettings deviceSettings) {
        Device device = this.getDeviceBySN(sn);
        if (!device.getSn().equals(sn)) {
            return;
        }

        DeviceSettings whereDeviceSettings = new DeviceSettings();
        whereDeviceSettings.setDeviceId(device.getId());
        QueryWrapper<DeviceSettings> queryWrapper = new QueryWrapper<>();
        queryWrapper.setEntity(whereDeviceSettings);

        deviceSettingsMapper.update(deviceSettings, queryWrapper);
    }

    /**
     * 判断是否拥有此设备权限
     * 
     * @param deviceId
     * @return
     */
    public void checkDeviceByCuruser(Long deviceId) {

        Node node = this.getDeviceNodeInfo(deviceId);
        if (node == null) {
            throw new BusinessException("无权限");
        }

        Long uid = RequestUtil.getUid();
        nodeService.checkNodeByNodeid(uid, node.getId());
    }

    /**
     * 判断是否拥有此设备权限
     * 
     * @param deviceIds
     */
    public void checkDeviceByCuruser(List<Long> deviceIds) {
        for (Long item : deviceIds) {
            this.checkDeviceByCuruser(item);
        }
    }

    /**
     * 删除设备
     * 
     * @param user
     * @param deviceId
     */
    public void deleteDevice(User user, Long deviceId) {

        Device device = this.getDeviceById(deviceId);
        if (device == null) {
            throw new BusinessException();
        }

        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("deviceId", deviceId);
        nodeDeviceMapper.deleteByMap(columnMap);

        tunnelService.delTunnelByCurUserDeviceid(deviceId);
        deviceMapper.deleteById(deviceId);
        logger.info("del device success,uid:{}, did:{}", user.getId(), deviceId);
    }

    /**
     * 获取操作系统
     * 
     * @param os
     * @return
     */
    private String makeOSType(String os) {
        if (StringUtils.isEmpty(os)) {
            return "unknow";
        }

        if (os.toLowerCase().indexOf("win") != -1) {
            return "win";
        }

        if (os.toLowerCase().indexOf("linux") != -1) {
            return "linux";
        }

        if (os.toLowerCase().indexOf("darwin") != -1) {
            return "mac";
        }

        return "unknow";
    }

    /**
     * 设备挂载
     * 
     * @param sn
     * @param name
     * @param ip
     * @param os
     */
    public void bootDevice(String sn, String name, String ip, String os) {

        if (StringUtils.isEmpty(sn) || StringUtils.isEmpty(name)) {
            throw new BusinessException();
        }

        Device devcie = this.getDeviceBySN(sn);
        if (devcie != null) {
            Device update = new Device();
            update.setId(devcie.getId());
            update.setName(name);
            update.setIp(ip);
            update.setOs(makeOSType(os));
            deviceMapper.updateById(update);
            return;
        }

        Long unknowNodeId = configService.getUnknowNodeId();

        devcie = new Device();
        devcie.setOs(makeOSType(os));
        devcie.setSn(sn);
        devcie.setName(name);
        devcie.setCtime(new Date());
        devcie.setIp(ip);
        devcie.setIsprober(Status.YES);
        devcie.setSort(devcie.getCtime().getTime());
        deviceMapper.insert(devcie);

        NodeDevice nodeDevice = new NodeDevice();
        nodeDevice.setDeviceId(devcie.getId());
        nodeDevice.setNodeId(unknowNodeId);
        nodeDeviceMapper.insert(nodeDevice);

        logger.info("device boot success,sn:{},name:{}", sn, name);
    }

    /**
     * 根据设备节点id获取所有设备
     * 
     * @param nodeId
     * @param isonline
     * @param devdesc
     * @param ip
     * @param name
     * @return
     */
    public List<Device> getListNodeDeviceByNodeid(Long nodeId, String name, String ip, String devdesc, String isonline) {

        List<Node> listNode = nodeService.getListNodeByNodeid(nodeId);
        if (listNode.isEmpty()) {
            return new ArrayList<Device>();
        }

        List<Long> nodeids = new ArrayList<Long>();
        listNode.forEach((item) -> {
            nodeids.add(item.getId());
        });

        QueryWrapper<NodeDevice> queryWrapperNodeDevice = new QueryWrapper<NodeDevice>();
        queryWrapperNodeDevice.in("nodeId", nodeids);
        List<NodeDevice> listNodeDevice = nodeDeviceMapper.selectList(queryWrapperNodeDevice);

        if (listNodeDevice.isEmpty()) {
            return new ArrayList<Device>();
        }

        List<Long> ids = new ArrayList<Long>();
        listNodeDevice.forEach((item) -> {
            ids.add(item.getDeviceId());
        });

        QueryWrapper<Device> queryWrapperDevice = new QueryWrapper<>();
        queryWrapperDevice.in("id", ids);
        queryWrapperDevice.orderByDesc("sort");
        if (!StringUtils.isEmpty(ip)) {
            queryWrapperDevice.like("ip", ip);
        }

        if (!StringUtils.isEmpty(name)) {
            queryWrapperDevice.like("name", name);
        }

        if (!StringUtils.isEmpty(devdesc)) {
            queryWrapperDevice.like("devdesc", devdesc);
        }

        queryWrapperDevice.orderByDesc("id");
        List<Device> retList = deviceMapper.selectList(queryWrapperDevice);

        for (int i = 0; i < retList.size(); i++) {
            Device device = retList.get(i);
            device.setPassword(null);
            if (device.getIsprober().equals(Status.YES)) {
                device.setIsonline(deviceSessionService.deviceIsOnline(device.getId()));
                device.setIsremote(natService.isRemoteingByDeviceSN(device.getSn()));
            } else {
                device.setIsremote(virtulNatService.isRemoteingByDeviceSN(device.getSn()));
            }

            if (isonline.equals("none")) {
                continue;
            }

            if (isonline.equals("online")) {
                if (device.getIsprober() == Status.NO) {
                    continue;
                }
                if (!device.getIsonline()) {
                    retList.remove(i);
                    i--;
                }
                continue;
            }

            if (isonline.equals("offline")) {
                if (device.getIsprober() == Status.NO || device.getIsonline()) {
                    retList.remove(i);
                    i--;
                }
                continue;
            }

            if (isonline.equals("ing")) {
                if (!device.getIsremote()) {
                    retList.remove(i);
                    i--;
                }
                continue;
            }
        }

        return retList;
    }

    /**
     * 根据设备获取节点信息
     * 
     * @param deviceId
     * @return
     */
    public Node getDeviceNodeInfo(Long deviceId) {
        NodeDevice nodeDevice = new NodeDevice();
        nodeDevice.setDeviceId(deviceId);
        QueryWrapper<NodeDevice> queryWrapper = new QueryWrapper<NodeDevice>();
        queryWrapper.setEntity(nodeDevice);
        NodeDevice tempNodeDevice = nodeDeviceMapper.selectOne(queryWrapper);

        if (tempNodeDevice == null) {
            return null;
        }

        return nodeService.getNodeById(tempNodeDevice.getNodeId());
    }

    /**
     * 设备置顶
     * 
     * @param deviceId
     */
    public void topDevice(Long deviceId) {
        Device device = new Device();
        device.setId(deviceId);
        device.setSort(new Date().getTime());
        deviceMapper.updateById(device);

        logger.info("update device to top success,id:{},operid:{}", deviceId, RequestUtil.getUid());
    }

    /**
     * 获取设备状态
     * 
     * @param ids
     * @return
     */
    public Object getListDeviceState(List<Long> ids) {
        Map<Long, Object> info = new HashMap<Long, Object>();

        for (Long item : ids) {
            info.put(item, getSateInfoByDeviceid(item));
        }

        return info;
    }

    /**
     * 获取设备状态
     * 
     * @param deviceId
     * @return
     */
    public Map<String, Object> getSateInfoByDeviceid(Long deviceId) {
        Device device = this.getDeviceById(deviceId);
        if (device == null) {
            return null;
        }

        Map<String, Object> sateInfo = new HashMap<String, Object>();
        if (device.getIsprober().equals(Status.YES)) {
            sateInfo.put("isonline", deviceSessionService.deviceIsOnline(device.getId()));
            sateInfo.put("isremote", natService.isRemoteingByDeviceSN(device.getSn()));
        } else {
            sateInfo.put("isremote", virtulNatService.isRemoteingByDeviceSN(device.getSn()));
        }

        return sateInfo;
    }

    /**
     * 获取设备总数量
     * 
     * @return
     */
    public Map<String, Integer> getDeviceCountInfo() {
        Map<String, Integer> info = new HashMap<String, Integer>();
        info.put("deviceAllCount", deviceMapper.selectCount(null));

        List<Device> list = deviceMapper.selectList(null);
        int offline = 0;
        for (int i = 0; i < list.size(); i++) {
            Device device = list.get(i);
            if (device.getIsprober().equals(Status.NO)) {
                continue;
            }

            if (deviceSessionService.deviceIsOnline(device.getId())) {
                continue;
            }

            offline++;
        }

        info.put("deviceAllOffline", offline);
        return info;
    }

}
